#include "stdafx.h"
#include "FastBlockQueue.h"


FastBlockQueue* FastBlockQueue::Create(HANDLE hQuit)
{
	return new FastBlockQueue(hQuit);
}


FastBlockQueue::FastBlockQueue(HANDLE hQuit)
:m_current(0),
m_end(0),
m_hEvent(::CreateEvent(NULL,TRUE,FALSE,NULL)),
m_hQuit(hQuit)
{
}

FastBlockQueue::~FastBlockQueue()
{
	::CloseHandle(m_hEvent);
	m_hEvent = 0;
}

void FastBlockQueue::Push(QueueItem const& data)
{
	m_cs.Lock();
	memcpy(m_datas+(m_end%DATA_CAPACITY), &data, sizeof(QueueItem));
	m_end++;
	m_cs.Unlock();
	::SetEvent(m_hEvent);
}

QueueItem& FastBlockQueue::Pop(bool& quitFlag)
{
	quitFlag = false;
	HANDLE handles[] = {m_hEvent,m_hQuit};
	while (1)
	{
		DWORD rtn = ::WaitForMultipleObjects(2,handles,FALSE,INFINITE);
		if (WAIT_OBJECT_0 == rtn)
		{
			m_cs.Lock();
			if (IsEmpty())
			{
				m_cs.Unlock();
				continue;
			}
			break;
		}
		else 
		{
			quitFlag = true;
			return m_datas[0];
		}
	}

	QueueItem& result = m_datas[m_current%DATA_CAPACITY];
	m_current++;

	if (IsEmpty())
	{
		::ResetEvent(m_hEvent);
	}
	m_cs.Unlock();
	return result;
}

bool FastBlockQueue::AlertablePop(bool& quitFlag,QueueItem& item)
{
	quitFlag = false;
	HANDLE handles[] = {m_hEvent,m_hQuit};
	while (1)
	{
		DWORD rtn = ::WaitForMultipleObjectsEx(2,handles,FALSE,INFINITE,TRUE);
		if (WAIT_OBJECT_0 == rtn)
		{
			m_cs.Lock();
			if (IsEmpty())
			{
				m_cs.Unlock();
				continue;
			}
			break;
		}
		else if(WAIT_IO_COMPLETION == rtn)
		{
			return true;
		}
		else 
		{
			quitFlag = true;
			item = m_datas[0];
			return false;
		}
	}

	item = m_datas[m_current%DATA_CAPACITY];
	m_current++;

	if (IsEmpty())
	{
		::ResetEvent(m_hEvent);
	}
	m_cs.Unlock();
	return false;
}